#ifndef CLIENTASYCREQUEST_H_
#define CLIENTASYCREQUEST_H_

#include "scatu/ClientRequests.h"

namespace scatu {
 
template<TServerFunction Function, typename ReturnType, typename ArgsType>
class RAsynchronousRequest<EClient, Function, ReturnType, ArgsType>
  : public RClientRequestCommon
    {
public:
    RAsynchronousRequest() : RClientRequestCommon(Function), iArgsBuf(NULL), iSize(iSizeInt) {}
    
    void Close()
        {
        delete iArgsBuf;
        }
    
    void CallL(RSessionBase & aSession, ArgsType const & aArgs, TRequestStatus & aStatus)
        {
        // Retry once if server has terminated
        TRAPD(err, DoCallL(aSession, aArgs, aStatus));
        if(err == KErrServerTerminated)
            {
            User::LeaveIfError(aSession.Connect());
            DoCallL(aSession, aArgs, aStatus);
            }
        else
            { User::LeaveIfError(err); }
        }
    
    void GetResult(RSessionBase & aSession, ReturnType & aRet)
        {
        DeleteArgs();
        
        HBufC8 * returnBuf = ReadReturnValueLC(aSession, iSize());
        aRet.DeserializeL(*returnBuf);
        CleanupStack::PopAndDestroy(returnBuf);
        }
    
private:
    
    void DoCallL(RSessionBase & aSession, ArgsType const & aArgs, TRequestStatus & aStatus)
        {
        DeleteArgs();
    
        iArgsBuf = aArgs.SerializeL();
        aSession.SendReceive(Function, TIpcArgs(iArgsBuf, &iSize), aStatus);
        }
    
    void DeleteArgs()
        {
        delete iArgsBuf;
        iArgsBuf = NULL;
        }
    
    HBufC8 * iArgsBuf;
    TPckg<TInt> iSize;
    TInt iSizeInt;
    };

} // namespace scatu


#endif /* CLIENTASYCREQUEST_H_ */
